package mirrormonkey.rpc.module;

import mirrormonkey.core.module.CoreModule;
import mirrormonkey.framework.SyncAppState;
import mirrormonkey.framework.module.MirrorMonkeyModule;
import mirrormonkey.rpc.RpcSpecification;
import mirrormonkey.rpc.annotations.RpcAnnotationPresets;
import mirrormonkey.rpc.messages.RpcCallMessage;
import mirrormonkey.rpc.messages.RpcErrorMessage;
import mirrormonkey.rpc.messages.RpcResultMessage;
import mirrormonkey.rpc.proxy.EntityProxy;
import mirrormonkey.rpc.proxy.RpcInvocationHandler;

import com.jme3.network.serializing.Serializer;

public class RpcModule extends MirrorMonkeyModule {

	public static final Class<?>[] RPC_MESSAGES = { RpcCallMessage.class,
			RpcResultMessage.class, RpcErrorMessage.class };

	public final RpcCallListener callListener;

	public final RpcResultListener responseListener;

	public final RpcErrorListener errorListener;

	public final CallRegistry callRegistry;

	public RpcModule(SyncAppState appState) {
		this(appState, new CallRegistry());
	}

	public RpcModule(SyncAppState appState, CallRegistry callRegistry) {
		this(appState, new RpcCallListener(appState.entityProvider),
				new RpcResultListener(callRegistry), new RpcErrorListener(
						callRegistry), callRegistry);
	}

	public RpcModule(SyncAppState appState, RpcCallListener callListener,
			RpcResultListener responseListener, RpcErrorListener errorListener,
			CallRegistry callRegistry) {
		super(appState);

		appState.entityProvider.parser
				.parsePresetClass(RpcAnnotationPresets.class);

		for (Class<?> i : RPC_MESSAGES) {
			Serializer.registerClass(i);
		}

		this.callListener = callListener;
		this.responseListener = responseListener;
		this.errorListener = errorListener;
		this.callRegistry = callRegistry;

		appState.eventManager.addMessageListener(callListener,
				RpcCallMessage.class);
		appState.eventManager.addMessageListener(responseListener,
				RpcResultMessage.class);
		appState.eventManager.addMessageListener(errorListener,
				RpcErrorMessage.class);
	}

	public <T extends RpcSpecification> EntityProxy<T> createRpcProxy(
			Class<T> spec) {
		return new RpcInvocationHandler(this, spec,
				appState.getModule(CoreModule.class));
	}

	@Override
	public void update(float tpf) {
		callRegistry.update(tpf);
	}

}
